using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.Runtime.InteropServices;
using System.IO;

namespace BodySoundSimulator.Training.PerformanceTester
{
	public partial class PerformanceTesterDlg : Form
	{
		#region Fields
		Pen extractedLocationPen = new Pen(Color.Red);
		Pen markedLocationPen = new Pen(Color.Blue);

		List<TestData> testData = new List<TestData>();
		List<Bitmap> extractedImages = new List<Bitmap>();
		List<StethLocationData> extractedLocationData = new List<StethLocationData>();

		static int frameIndex = 0;

		Thread videoCapturingThread;
		LoadingDialog loadlingDialog = new LoadingDialog();

		delegate void UpdateFrameViewerControls();
		#endregion

		#region Constructors
		public PerformanceTesterDlg()
		{
			InitializeComponent();
		}
		#endregion

		#region Private methods

		private void SourceImagePushed(int width, int height, IntPtr imageDataPointer)
		{
			int size = height * width;
			byte[] imageData = new byte[size];
			Marshal.Copy(imageDataPointer, imageData, 0, size);
			Bitmap bitmap = BitmapCreationHelper.GetBitmapFromPixelData(imageData, width, height);
			extractedImages.Add(bitmap);
		}

		private void LocationDataPushed(IntPtr locationDataPtr)
		{
			StethLocationData locationData = new StethLocationData();
			Marshal.PtrToStructure(locationDataPtr, locationData);
			extractedLocationData.Add(locationData);
		}

		private void CapturingFinished()
		{
			for (int index = 0; index < extractedImages.Count; index++)
			{
				TestData dataItem = new TestData();
				dataItem.Image = this.extractedImages[index];
				dataItem.ExtractedStethLocation = StethLocationDataManipulator.GetMappedStethLocation(this.extractedLocationData[index]);
				dataItem.MarkedStethLocation = dataItem.ExtractedStethLocation;

				this.testData.Add(dataItem);
			}
			frameIndex = 0;
			if (testData.Count > 0)
			{
				if (this.InvokeRequired)
				{
					this.BeginInvoke(new UpdateFrameViewerControls(UpdateFrameViewer));
				}
				else
				{
					UpdateFrameViewer();
				}
			}
		}

		private void UpdateFrameViewer()
		{
			this.picBoxVideo.Image = testData[frameIndex].Image;
			this.picBoxVideo.Invalidate();
			this.picBoxMarking.Invalidate();
			this.lblFrameNumber.Text = string.Format("Frame {0}/{1}", frameIndex, testData.Count - 1);
			this.loadlingDialog.Close();
		}

		private void GotoFrame()
		{
			int fremeNumber;
			if (int.TryParse(this.txtFrameNumber.Text, out fremeNumber))
			{
				if (fremeNumber >= 0
					&& fremeNumber < this.testData.Count)
				{
					frameIndex = fremeNumber;
					UpdateFrameViewer();
				}
			}
		}
		#endregion

		#region UI event handlers

		private void btnLoad_Click(object sender, EventArgs e)
		{
			OpenFileDialog openFileDlg = new OpenFileDialog();
			if (openFileDlg.ShowDialog() == DialogResult.OK)
			{
				this.txtFileName.Text = openFileDlg.FileName;
				if (!string.IsNullOrEmpty(this.txtFileName.Text))
				{
					this.testData.Clear();
					this.extractedImages.Clear();
					this.extractedLocationData.Clear();
					StringBuilder builder = new StringBuilder(this.txtFileName.Text);
					videoCapturingThread = new Thread(new ParameterizedThreadStart(StartRecording));
					videoCapturingThread.Start(builder);
					loadlingDialog = new LoadingDialog();
					loadlingDialog.ShowDialog();
				}
			}
		}

		private void StartRecording(object builderObject)
		{
			StringBuilder builder = builderObject as StringBuilder;
			OpenCvAdapterNativeMethods.StartCapturingFromFile(builder,
							new OpenCvAdapterNativeMethods.ImagePushedDelegate(SourceImagePushed),
							new OpenCvAdapterNativeMethods.StethLocationDataPushedDelegate(LocationDataPushed),
							new OpenCvAdapterNativeMethods.CapturingFinishedDelegate(CapturingFinished));
		}

		private void btnPrevious_Click(object sender, EventArgs e)
		{
			frameIndex--;
			if (frameIndex < 0)
			{
				frameIndex = 0;
			}
			UpdateFrameViewer();
		}

		private void btnNext_Click(object sender, EventArgs e)
		{
			frameIndex++;
			if (frameIndex >= this.testData.Count)
			{
				frameIndex = testData.Count - 1;
			}
			UpdateFrameViewer();
		}

		private void picBoxMarking_Paint(object sender, PaintEventArgs e)
		{
			if (this.testData.Count > 0)
			{
				int width = 5;
				Graphics g = e.Graphics;
				g.TranslateTransform(150, 50);
				g.DrawRectangle(extractedLocationPen,
					this.testData[frameIndex].ExtractedStethLocation.X - width / 2,
					this.testData[frameIndex].ExtractedStethLocation.Y + width / 2,
					width,
					width);
				g.DrawRectangle(markedLocationPen,
					this.testData[frameIndex].MarkedStethLocation.X - width / 2,
					this.testData[frameIndex].MarkedStethLocation.Y + width / 2,
					width,
					width);
			}
		}

		private void picBoxMarking_MouseDown(object sender, MouseEventArgs e)
		{
			if (this.testData.Count > 0)
			{
				PointF newPoint = new PointF(e.Location.X - 150, e.Location.Y -  50);
				this.testData[frameIndex].MarkedStethLocation = newPoint;
				this.picBoxMarking.Invalidate();
			}
		}		
		
		private void btnSave_Click(object sender, EventArgs e)
		{
			StringBuilder builder = new StringBuilder();
			foreach (TestData dataItem in this.testData)
			{
				builder.AppendLine(dataItem.ErrorDistance.ToString());
			}
			string fileName = Path.Combine(Path.GetDirectoryName(this.txtFileName.Text), Path.GetFileNameWithoutExtension(this.txtFileName.Text) + "_ErrorLog.txt");

			File.WriteAllText(fileName, builder.ToString());
		}

		private void btnOK_Click(object sender, EventArgs e)
		{
			this.DialogResult = DialogResult.OK;
		}

		private void btnCancel_Click(object sender, EventArgs e)
		{
			this.DialogResult = DialogResult.Cancel;
		}		

		private void txtFrameNumber_KeyDown(object sender, KeyEventArgs e)
		{
			if (e.KeyData == Keys.Enter)
			{
				GotoFrame();
			}
		}

		private void btnSaveImage_Click(object sender, EventArgs e)
		{
			if (this.testData != null
				&& this.testData.Count > 0)
			{
				SaveFileDialog saveDlg = new SaveFileDialog();
				saveDlg.Filter = "JPEG Files|*.jpg";
				saveDlg.FileName = string.Format("frame{0}", frameIndex);
				if (saveDlg.ShowDialog() == DialogResult.OK)
				{
					this.testData[frameIndex].Image.Save(saveDlg.FileName);
				}
			}
		}		
		#endregion
	}
}